package com.ccplay.dataservice.web.payment;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.oxygen.constants.Constant;
import com.oxygen.dto.ApiFinalResponse;
import com.oxygen.enums.ApiMethodEnum;
import com.oxygen.enums.ApiMsgEnum;
import com.oxygen.util.JsonUtil;
import com.oxygen.util.RSAUtil;
import com.ccplay.dataservice.web.BaseAction;
import com.google.gson.reflect.TypeToken;

@Controller
@RequestMapping(value = { "/api/v2/payment" })
public class AlipayCallbackAction extends BaseAction {
	private static final Logger loger = Logger.getLogger(AlipayCallbackAction.class);
	/**
	 * 支付宝消息验证地址
	 */
	private static final String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";
	private static String input_charset = "utf-8";
	private static String sign_type = "RSA";

	/**
	 * 支付宝回调
	 * 
	 * @param req
	 * @param rsp
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@SuppressWarnings("rawtypes")
	@RequestMapping(value = { "/alipayCallback/{paymentId}", "/alipayCallback/{paymentId}/" })
	public String alipayCallback(@PathVariable String paymentId, HttpServletRequest req, HttpServletResponse rsp) throws UnsupportedEncodingException {

		// 获取支付宝POST过来反馈信息
		Map<String, String> params = new HashMap<String, String>();
		Map requestParams = req.getParameterMap();
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			// 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			params.put(name, valueStr);
		}
		loger.info(params);
		// 获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		// 商户订单号
		String out_trade_no = new String(req.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
		// 支付宝交易号
		String trade_no = new String(req.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
		// 交易状态
		String trade_status = new String(req.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
		// 获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
		if (verify(params)) {// 验证成功
			loger.info("alipayCallback验证签名结果[成功].");
			// ////////////////////////////////////////////////////////////////////////////////////////
			Map<String, Object> appendMap = new HashMap<String, Object>();
			appendMap.put(Constant.API_KEY, "android_payment_sdk");
			appendMap.put("paymentDesc", JsonUtil.objectToJson(params));
			appendMap.put("paymentChannelCode", "alipay");
			appendMap.put("transaction_no", out_trade_no);
			appendMap.put("paymentId", paymentId);
			appendMap.put("paymentTransactionNo", trade_no);
			if (!"WAIT_BUYER_PAY".equals(trade_status.trim())) {
				if ("TRADE_SUCCESS".equals(trade_status.trim())) {
					appendMap.put("status", "paid");
				} else {
					appendMap.put("status", "pay_fail");
				}
				String json = this.callApi(ApiMethodEnum.PAYMENT_PAYMENTCALLBACK, appendMap);
				Type type = new TypeToken<Map<String, ApiFinalResponse<Object>>>() {
				}.getType();
				Map<String, ApiFinalResponse<Object>> tempMap = JsonUtil.jsonToObject(json, type);
				if (tempMap != null && tempMap.get(ApiMethodEnum.PAYMENT_PAYMENTCALLBACK.getCode()) != null) {
					String code = tempMap.get(ApiMethodEnum.PAYMENT_PAYMENTCALLBACK.getCode()).getCode();
					if (ApiMsgEnum.SUCCESS.getCode().equals(code)) {
						return this.outputJson("success", rsp);
					}
				}
				return this.outputJson("fail", rsp);
			}
			return this.outputJson("success", rsp); // 请不要修改或删除
			// ////////////////////////////////////////////////////////////////////////////////////////
		} else {// 验证失败
			loger.error("alipayCallback验证签名结果[失败].");
			return this.outputJson("fail", rsp);
		}
	}

	/**
	 * 验证消息是否是支付宝发出的合法消息
	 * 
	 * @param params
	 *            通知返回来的参数数组
	 * @return 验证结果
	 */
	public boolean verify(Map<String, String> params) {

		// 判断responsetTxt是否为true，isSign是否为true
		// responsetTxt的结果不是true，与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
		// isSign不是true，与安全校验码、请求时的参数格式（如：带自定义参数等）、编码格式有关
		String responseTxt = "true";
		if (params.get("notify_id") != null) {
			String notify_id = params.get("notify_id");
			responseTxt = verifyResponse(notify_id);
		}
		String sign = "";
		if (params.get("sign") != null) {
			sign = params.get("sign");
		}
		boolean isSign = getSignVeryfy(params, sign);

		// 写日志记录（若要调试，请取消下面两行注释）
		// String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign +
		// "\n 返回回来的参数：" + AlipayCore.createLinkString(params);
		// AlipayCore.logResult(sWord);

		if (isSign && responseTxt.equals("true")) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 根据反馈回来的信息，生成签名结果
	 * 
	 * @param Params
	 *            通知返回来的参数数组
	 * @param sign
	 *            比对的签名结果
	 * @return 生成的签名结果
	 */
	private boolean getSignVeryfy(Map<String, String> Params, String sign) {
		// 过滤空值、sign与sign_type参数
		Map<String, String> sParaNew = paraFilter(Params);
		// 获取待签名字符串
		String preSignStr = createLinkString(sParaNew);
		// 获得签名验证结果
		boolean isSign = false;
		if (sign_type.equals("RSA")) {
			isSign = RSAUtil.verify(preSignStr, sign, alipayRsaPublic, input_charset);
		}
		return isSign;
	}

	/**
	 * 获取远程服务器ATN结果,验证返回URL
	 * 
	 * @param notify_id
	 *            通知校验ID
	 * @return 服务器ATN结果 验证结果集： invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空 true
	 *         返回正确信息 false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
	 */
	private String verifyResponse(String notify_id) {
		// 获取远程服务器ATN结果，验证是否是支付宝服务器发来的请求

		String partner = alipayPartner;
		String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;

		return checkUrl(veryfy_url);
	}

	/**
	 * 获取远程服务器ATN结果
	 * 
	 * @param urlvalue
	 *            指定URL路径地址
	 * @return 服务器ATN结果 验证结果集： invalid命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空 true
	 *         返回正确信息 false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
	 */
	private String checkUrl(String urlvalue) {
		String inputLine = "";

		try {
			URL url = new URL(urlvalue);
			HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
			inputLine = in.readLine().toString();
		} catch (Exception e) {
			e.printStackTrace();
			inputLine = "";
		}

		return inputLine;
	}

	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param sArray
	 *            签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	public Map<String, String> paraFilter(Map<String, String> sArray) {

		Map<String, String> result = new HashMap<String, String>();

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}

		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {
				continue;
			}
			result.put(key, value);
		}

		return result;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public String createLinkString(Map<String, String> params) {

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}

	// /**
	// * 写日志，方便测试（看网站需求，也可以改成把记录存入数据库）
	// *
	// * @param sWord
	// * 要写入日志里的文本内容
	// */
	// public static void logResult(String sWord) {
	// FileWriter writer = null;
	// try {
	// writer = new FileWriter(AlipayConfig.log_path + "alipay_log_" +
	// System.currentTimeMillis() + ".txt");
	// writer.write(sWord);
	// } catch (Exception e) {
	// e.printStackTrace();
	// } finally {
	// if (writer != null) {
	// try {
	// writer.close();
	// } catch (IOException e) {
	// e.printStackTrace();
	// }
	// }
	// }
	// }
	//
	// /**
	// * 生成文件摘要
	// * @param strFilePath 文件路径
	// * @param file_digest_type 摘要算法
	// * @return 文件摘要结果
	// */
	// public static String getAbstract(String strFilePath, String
	// file_digest_type) throws IOException {
	// PartSource file = new FilePartSource(new File(strFilePath));
	// if(file_digest_type.equals("MD5")){
	// return DigestUtils.md5Hex(file.createInputStream());
	// }
	// else if(file_digest_type.equals("SHA")) {
	// return DigestUtils.sha256Hex(file.createInputStream());
	// }
	// else {
	// return "";
	// }
	// }
}
